use cgmath::{Vector2, Zero};

use crate::renderer::*;

use crate::camera::*;
use crate::util::*;
use crate::{TEXTURES, WIDTH, HEIGHT};

// there shall be two sets of background layers
// one is followed by another, rolling from the right to the left
// each layer has 4 component: cloud, ground, moon, star
pub struct Background {
    size: Vector2<f64>,

    position1: Vec<Vector2<f64>>,
    velocity1: Vec<Vector2<f64>>,

    position2: Vec<Vector2<f64>>,
    velocity2: Vec<Vector2<f64>>,

    textures: Vec<Texture>,
}

impl Background {
    pub fn new() -> Self {
        Self {
            size: Vector2::new(2400.0, 600.0),

            position1: vec![Vector2::zero(); 4],
            velocity1: vec![Vector2::zero(); 4],

            position2: vec![Vector2::zero(); 4],
            velocity2: vec![Vector2::zero(); 4],

            textures: Vec::new(),
        }
    }

    pub fn initialize(
        &mut self,
    ) {
        let texture_names: Vec<String> = vec![
            "LAYER_GROUND".into(),
            "LAYER_MOON".into(),
            "LAYER_STAR".into(),
            "LAYER_CLOUD".into(),
        ];

        for texture_name in texture_names.iter() {
            let texture = TEXTURES()[texture_name].clone();
            self.textures.push(texture);
        }

        self.position1 = vec![
            Vector2::new(0.0, -100.0),
            Vector2::new(0.0, -200.0),
            Vector2::new(0.0, -100.0),
            Vector2::new(0.0, -100.0),
        ];
        self.position2 = vec![
            Vector2::new(0.0, -100.0),
            Vector2::new(0.0, -200.0),
            Vector2::new(0.0, -100.0),
            Vector2::new(0.0, -100.0),
        ];
        for i in 0..texture_names.len() {
            self.position2[i].x = self.position1[i].x + self.size.x;
        }
        self.velocity1 = vec![
            Vector2::new(-400.0, 0.0),
            Vector2::new(-50.0, 0.0),
            Vector2::new(-80.0, 0.0),
            Vector2::new(-160.0, 0.0),
        ];
        self.velocity2 = vec![
            Vector2::new(-400.0, 0.0),
            Vector2::new(-50.0, 0.0),
            Vector2::new(-80.0, 0.0),
            Vector2::new(-160.0, 0.0),
        ];
    }

    pub fn update(
        &mut self,
        delta_time: f64,
    ) {
        for i in 0..self.textures.len() {
            self.position1[i] = self.position1[i] + self.velocity1[i] * delta_time;
            self.position2[i] = self.position2[i] + self.velocity2[i] * delta_time;
            if self.position1[i].x < -500.0 - 0.5 * self.size.x {
                self.position1[i].x = self.position2[i].x + self.size.x;
            }
            if self.position2[i].x < -500.0 - 0.5 * self.size.x {
                self.position2[i].x = self.position1[i].x + self.size.x;
            }
        }
    }
    
    pub fn draw(
        &self,
        renderer: &mut Renderer,
        camera: &Camera,
    ) {
        for i in 0..self.textures.len() {
            let leftup_world_1 = Vector2::new(
                self.position1[i].x - self.size.x * 0.5,
                self.position1[i].y + self.size.y,
            );
            let rightdown_world_1 = Vector2::new(
                self.position1[i].x + self.size.x * 0.5,
                self.position1[i].y,
            );
            let leftup_world_2 = Vector2::new(
                self.position2[i].x - self.size.x * 0.5,
                self.position2[i].y + self.size.y,
            );
            let rightdown_world_2 = Vector2::new(
                self.position2[i].x + self.size.x * 0.5,
                self.position2[i].y,
            );

            let leftup_screen_1 = world_to_screen(
                &leftup_world_1,
                camera,
                &Vector2::new(WIDTH as _, HEIGHT as _)
            );
            let rightdown_screen_1 = world_to_screen(
                &rightdown_world_1,
                camera,
                &Vector2::new(WIDTH as _, HEIGHT as _)
            );
            let leftup_screen_2 = world_to_screen(
                &leftup_world_2,
                camera,
                &Vector2::new(WIDTH as _, HEIGHT as _)
            );
            let rightdown_screen_2 = world_to_screen(
                &rightdown_world_2,
                camera,
                &Vector2::new(WIDTH as _, HEIGHT as _)
            );

            renderer.draw_texture(
                &leftup_screen_1,
                &rightdown_screen_1,
                &self.textures[i],
            );

            renderer.draw_texture(
                &leftup_screen_2,
                &rightdown_screen_2,
                &self.textures[i],
            );
        }
    }

    pub fn get_ground_position(&self) -> Vector2<f64> {
        self.position1[0]
    }

    pub fn get_ground_velocity(&self) -> Vector2<f64> {
        self.velocity1[0]
    }
}